package com.yangchuang.openpicture.interceptor;


import com.yangchuang.openpicture.communication.ResultCode;
import com.yangchuang.openpicture.constant.JwtTokenClaimsConstants;
import com.yangchuang.openpicture.constant.ThreadLocalConstants;
import com.yangchuang.openpicture.exception.BussinessException;
import com.yangchuang.openpicture.service.TokenBlacklistService;
import com.yangchuang.openpicture.util.BaseContext;
import com.yangchuang.openpicture.util.JwtUtil;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.JwtException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.HandlerInterceptor;

@Component
@Slf4j
public class JwtInterceptor implements HandlerInterceptor {
    private final JwtUtil jwtUtil;
    private final TokenBlacklistService blacklistService;

    public JwtInterceptor(JwtUtil jwtUtil, TokenBlacklistService blacklistService) {
        this.jwtUtil = jwtUtil;
        this.blacklistService = blacklistService;
    }



    //这个拦截器 拦截请求  对请求所携带的accesstoken 进行检查  放过哪些：
    //1. 注册  登录 因为是登陆后 才给前端返回两个token
    //2. 获取验证码 这是登录注册中的一部分
    //2. swagger文档
    //3. 请求刷新token接口 前端掉这个接口的时候 表示accesstoken已经过期了 这时候拦截，则死循环，token无法进行滑动刷新
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        log.info("请求路径: {}", request.getRequestURI());
        // 1. 从请求头中获取 token  [根据key,获取对应的value]
        String token = request.getHeader("Authorization");
        // 2. 检查 token 是否存在且格式正确
        if (!StringUtils.hasText(token) || !token.startsWith("Bearer ")) {
            throw new BussinessException(ResultCode.JWT_TOKEN_MISSING);
        }

        // 3. 检查token是否在黑名单中
        if (blacklistService.isBlacklisted(token)) {
            throw new BussinessException(ResultCode.InvalidToken);
        }

        try {
            // 4. 截取 "Bearer " 前缀，获取真正的 token
            String jwt = token.substring(7);
            Claims claims = jwtUtil.parseToken(jwt); //不报错 则说明 token的基本信息正确
            // 5. 将解析出的用户信息（如用户ID和 EMAIL ）存入 ThreadLocal，方便后续 Controller 使用
            BaseContext.set(ThreadLocalConstants.USER_ID, claims.get(JwtTokenClaimsConstants.USER_ID));
            BaseContext.set(ThreadLocalConstants.USER_ROLE, claims.get(JwtTokenClaimsConstants.USER_ROLE));
            //6. 验证通过，放行
            return true;
        } catch (ExpiredJwtException e) {
            // 全局异常处理器会捕获这个异常，并返回特定的状态码给前端
            throw new BussinessException(ResultCode.ExpiredToken);
        } catch (JwtException e) {
            // 捕获其他所有JWT相关的异常（如签名无效、格式错误）
            throw new BussinessException(ResultCode.InvalidToken);
        }
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        // 请求处理完成后，清理ThreadLocal，防止内存泄漏
        BaseContext.clear();
    }

}
